package solution;

import java.util.*;

import hex.HexMove;
import hex.HexState;

public class Rope {
	Point endPoint;
	Point endPoint2;
	ArrayList<Point> inBetweens;
	
	public Rope(Point p1, Point p2){
		endPoint = p1;
		endPoint2 = p2;
		inBetweens = findRope(endPoint, endPoint2);
		inBetweens.add(endPoint);
		inBetweens.add(endPoint2);
		System.out.println("size:" + inBetweens.size());
	}
	public Rope(int x1, int y1, int x2, int y2)
	{
		this(new Point(x1, y1), new Point(x2, y2));
	}
	
	private ArrayList<Point> findRope(Point first, Point last){
		if (Point.getDist(first, last) == 2)
		{
			return new ArrayList<Point>(Arrays.asList(getBothPathsBetweenPoints(first, last)));
		}
		if (Point.getDist(first, last) % 2 != 0 || Point.getDist(first, last) < 2)
		{
			return new ArrayList<Point>();
		}
		Point midPoint = new Point((first.x + last.x )/ 2, (first.y + last.y )/ 2);
		ArrayList<Point> points = new ArrayList<Point>();
		points.add(midPoint);
		points.addAll(findRope(first, midPoint));
		points.addAll(findRope(midPoint, last));
		return points;
	}
	
	public boolean isContinuous(int[][] board){
		for (int i = 0; i < inBetweens.size(); i++){
			boolean thisPoint = false;
			for (int j = 0; j < inBetweens.size(); j++){
				if (i==j){}
				else{
					Point first = inBetweens.get(i);
					Point second = inBetweens.get(j);
					if (hasTwoMovesBetween(first, second, board)){
						thisPoint = true;
						j = inBetweens.size();
					}
				}
				if (!thisPoint)return false;
			}
		}
		return false;
	}
	
	public boolean hasTwoMovesBetween(Point f, Point s, int[][] board){
		int dx = f.x-s.x;
		int dy = f.y-s.y;
		dy*=dy;
		dx*=dx;
		if (dx+dy!=2 || dx+dy!=5)return false;
		
		Point[] connectors = Rope.getBothPathsBetweenPoints(f, s);
		try{
			Point fi = connectors[0];
			Point se = connectors[1];
			if (board[fi.x][fi.y]== -1 || board[se.x][se.y]==-1) return false;
			return true;
		}
		catch(Exception e){
			return false;
		}
	}
	
	public boolean hasOneMoveBetween(Point f, Point s, int[][] board){
		int dx = f.x-s.x;
		int dy = f.y-s.y;
		dy*=dy;
		dx*=dx;
		if (dx+dy!=2 || dx+dy!=5)return false;
		
		Point[] connectors = Rope.getBothPathsBetweenPoints(f, s);
		try{
			Point fi = connectors[0];
			Point se = connectors[1];
			if (board[fi.x][fi.y]== -1 && board[se.x][se.y]==-1) return false;
			return true;
		}
		catch(Exception e){
			return false;
		}
	}
	//NOTE: Someone / something needs to check if past our endpoints are safe ie if we can connect to edge
	//Assuming that the rope end is 1 away from the edge.
	public boolean isClear() {
		System.out.println("got to isclear()");
		if(HexPlayer.lastMove == null)
			return true;
		return !(inBetweens.contains(HexPlayer.lastMove) || HexPlayer.lastMove.equals(endPoint) || HexPlayer.lastMove.equals(endPoint2));
	}
	
	
	//@precondition isClear() has returned false
	//@return point that connects the rope if possible, if not returns point (-1,-1)
	public Point nextMove(){
		if((Point.getDist(HexPlayer.lastMove, endPoint) % 2) != 0){
			for(Point possible : inBetweens){
				if(Point.getDist(possible, HexPlayer.lastMove) == 1 && (Point.getDist(possible, endPoint)%2) != 0){
					return possible;
				}				
			}			
		}
		return new Point(-1,-1);
	}
	public static Point[] getBothPathsBetweenPoints(Point f, Point s){
		int x = f.x+s.x, y = f.y+s.y;
		int xx = x/2, yy = y/2;
		Point[] i = {new Point(xx,yy), new Point(x-xx, y-yy)};
		return i;
	}
	public Rope cutRope(Point end)
	{
		if(Point.getDist(end, endPoint) > Point.getDist(end, endPoint2))
			endPoint2 = end;
		else
			endPoint = end;
		inBetweens = findRope(endPoint, endPoint2);
		return new Rope(0,0,0,0);
	}
	//Gets the empty point closest to the center of the rope that is unoccupied.
	public Point moveInside(HexState hs)
	{
		Point play = null;
		int totalDist = Point.getDist(endPoint, endPoint2);
		ArrayList<Point> possibles = new ArrayList<Point>();
		for(Point p: inBetweens)
		{
			if((Point.getDist(p, endPoint) % 2) == 0)
			{
				possibles.add(p);		
			}
		}
		for(Point p : possibles)
		{
			if(hs.moveOK(new HexMove(p.x, p.y)))
			{
				play = p;
				break;
			}		
		}
		if(play == null)
			play = new Point(-1,-1);
		
		System.out.println("from moveInside(): " + play);
		return play;
	}
	public Point completeRope(HexState hs){
		Point[] connectors = Rope.getBothPathsBetweenPoints(this.endPoint, this.endPoint2);
		int a=0;
		int b=1;
		for(int i=0;i<connectors.length/2;i++){
			Point fi = connectors[a+i];
			Point se = connectors[b+i];
			if (!(hs.board[fi.x][fi.y]== HexState.homeSym || hs.board[se.x][se.y] == HexState.homeSym))
			if (hs.board[fi.x][fi.y]== -1)
				return new Point(fi.x,fi.y);
			else 
				return new Point(se.x,se.y);
		}				
		return(new Point(-1,-1));
	}
}
